#ifndef _EDITOR_
#define _EDITOR_

#include <iostream>
#include <stdlib.h>
#include <deque>
#include <vector>
#include <cmath>

#include "SFML/Graphics.hpp"

#include "Scripting/Scripting.hpp"
#include "Graphics/Graphics.hpp"
#include "Content/Map.hpp"
#include "Content/MapManager.hpp"
#include "Graphics/Camera.hpp"
#include "Objects/Entity.hpp"
#include "Actions/Actions.hpp"
#include "Utilities/IntervalCounter.hpp"
#include "UI/Panels.hpp"
#include "EditorInstance.hpp"
#include "Actions/MapResizer.hpp"
#include "ScriptableInputHandler.hpp"
#include "Utilities/TandemTimer.hpp"
#include "Utilities/StringHelper.hpp"
#include "EditorRegion.hpp"
#include "EditorScriptEngine.hpp"

using namespace std;

/** 
* Cursor image
*/
enum Cursor{
    Arrow, FillCursor, MoveCursor, SelectCursor, PointerCursor
};

class Editor:public InterfaceEventHandler, public Scriptable{
private:
    sf::RenderWindow* window;
    Cursor cursor;
    static Editor* instance;

    sf::Clock editorTimer;
    unsigned int frameTime;
    
    //Input events
    void newMap();
    void mapTabClose(InterfaceElement* sender);
    void spriteSelected(BaseSprite* sprite);
    void selectTool(EditorInstance::Tool tool);
    void saveMap();
    void openMap(std::string mapname);
    void showOpenWindow();

    bool isLeftDown;

    //UI and graphics
    SpriteManager* editorSprites;
    SpriteManager* gameSprites;
    UIManager ui;
    virtual bool trapped(InterfaceEvent* event);
    SpriteSelectorPanel* spritePanel;
    
    IntervalCounter* fpsCounter;

    //Panels and UI
    RightPanel toolPanel;
    MapInfoPanel mapPanel;
    SpriteInfoPanel infoPanel;
    TileInfoPanel tilePanel;
    ActionHistoryPanel historyPanel;
    ClipboardPanel clipboardPanel;
    RegionPanel regionPanel;
    FileDialog* openFile;
    RegionWindow regionWindow;
    
    void showSpritePanel();
    void hideSpritePanel();
    bool mouseOverUI;

    IconButton brushButton;
    IconButton fillButton;
    IconButton marqueeButton;
    IconButton moveButton;
    IconButton saveButton;
    IconButton newMapButton;
    IconButton openMapButton;
    IconButton regionButton;
    
    //Engine
    GameDrawer* gameDrawer;
    Camera* camera;

    vector<EditorInstance*> instances;
    vector<MapTab*> tabs;

    EditorInstance* CM;

    //Action History
    TandemTimer undoTimer;
    void addAction(BaseAction* action);
    void undoAction();
    void redoAction();

    //Marquee options.
    //Is marquee being moved.
    bool marqueeMove;
    //Does a marquee exist.
    bool marqueeExists;
    //Is the mouse within marquee area.
    bool isMouseInMarquee;

    void drawMarquee();
    void updateMarqueeSize();
    void updateMarqueeLocation();

    //Input variables
    ScriptableInputHandler input;
    bool hasFocus;
    bool hasCleared;
    bool hasCut;
    bool hasPasted;
    unsigned int inputTimer;

    //Mouse position in previous frame
    int lastMouseX;
    int lastMouseY;

    //Mouse position in current frame.
    int mouseX;
    int mouseY;

    //Mouse tile position in previous frame
    int lastMouseTileX;
    int lastMouseTileY;
    //Mouse tile position in current frame
    int mouseTileX;
    int mouseTileY;

    //Tile the mouse was over in previous frame.
    int lastMouseTile;
    //Tile the mouse is over.
    int mouseTile;
    //Is the mouse over valid map area.
    bool mouseInMap;

    //Mouse position in the world.
    int mouseWorldX;
    int mouseWorldY;
    
    int mapTileX;
    int mapTileY;
    int mapTile;

    //Temporary region being worked with.
    int regionWidth;
    int regionHeight;
    int regionX;
    int regionY;
    
    //Is a region being resized.
    bool regionResize;
    bool regionResizeX;
    bool regionResizeY;
    
    //Is a region being moved.
    bool regionMove;
    
    EditorRegion* selectedRegion;
    EditorRegion* getMouseOverRegion();
    void updateRegion();

    //Scripting
    EditorScriptEngine scriptEngine;
public:

    Editor();

    void run();
    void handleInput();
    void handleMarqueeInput();
    void handleMoveInput();
    void handleFillInput();
    void handleRegionInput();
    void handleBrushInput();
    
    void updateMouseTile();
    void addMapInstance(Map* map, EditorRegionManager* regionManager);
    void selectEditorInstance(EditorInstance* editorInstance);

    void bind(lua_State* luaState);
    void push(lua_State* luaState);

    ~Editor();
};

#endif